/******************************************************************************
 * Copyright (c) 2022 Jaroslav Hensl                                          *
 *                                                                            *
 * Permission is hereby granted, free of charge, to any person                *
 * obtaining a copy of this software and associated documentation             *
 * files (the "Software"), to deal in the Software without                    *
 * restriction, including without limitation the rights to use,               *
 * copy, modify, merge, publish, distribute, sublicense, and/or sell          *
 * copies of the Software, and to permit persons to whom the                  *
 * Software is furnished to do so, subject to the following                   *
 * conditions:                                                                *
 *                                                                            *
 * The above copyright notice and this permission notice shall be             *
 * included in all copies or substantial portions of the Software.            *
 *                                                                            *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,            *
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES            *
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                   *
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT                *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,               *
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING               *
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR              *
 * OTHER DEALINGS IN THE SOFTWARE.                                            *
 *                                                                            *
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <bitstream.h>
#include <bpatcher.h>

#define PREFIX_MAX 255

const char *h_header = \
	"/****** Generated by " __FILE__ " ******/\n" \
	"/****** for regenaration run make fasmdiff ******/\n\n" \
	"#ifndef __VMM_%s_H__INCLUDED__\n" \
	"#define __VMM_%s_H__INCLUDED__\n\n";

const char *h_footer = "#endif /* __VMM_%s_H__INCLUDED__ */\n";

static size_t file_size(FILE *fp)
{
	size_t cur, end;
	
	cur = ftell(fp);
	fseek(fp, 0, SEEK_END);
	end = ftell(fp);
	fseek(fp, cur, SEEK_SET);
	
	return end;
}

int main(int argc, char *argv[])
{
	uint8_t *mem1 = NULL, *mem2 = NULL, *mem3 = NULL; /* buffer for fread */
	FILE *fp = NULL;
	size_t dumped_s, original_s, i, j;
	int status = EXIT_FAILURE;
	bitstream_t bs;
	char *dump_file = NULL;
	char *original_file = NULL;
	char *output_file = NULL;
	size_t ignore_begin = SIZE_MAX;
	size_t ignore_end   = SIZE_MAX;
	char *prefix = NULL;
	size_t prefix_len = 0;
	char prefix_upper[PREFIX_MAX];
	FILE *out = stdout;
	int out_open = 0;
	
	if(argc < 5)
	{
		printf("Usage: %s <prefix> <output.h> <dump.bin> <original.bin> [ignore space begin] [ignore space end]", argv[0]);
		return 0;
	}

  prefix        = argv[1];
  output_file   = argv[2];
	dump_file     = argv[3];
	original_file = argv[4];
	
	if(argc >= 6)
	{
		ignore_begin = strtoul(argv[5], NULL, 0);
	}
	
	if(argc >= 7)
	{
		ignore_end = strtoul(argv[6], NULL, 0);
	}
	
	prefix_len = strlen(prefix);
	if(prefix_len >= PREFIX_MAX)
	{
		prefix_len = PREFIX_MAX-1;
	}
	for(i = 0; i < prefix_len; i++)
	{
		prefix_upper[i] = toupper(prefix[i]);
	}
	prefix_upper[prefix_len] = '\0';
	

	fp = fopen(dump_file, "rb");
	if(fp)
	{
		dumped_s = file_size(fp);
		mem1 = malloc(dumped_s);
		mem2 = malloc(dumped_s);
		mem3 = bs_mem_alloc(&bs, bs_calc_size(dumped_s));
		
		if(strcmp(output_file, "-") != 0)
		{
			out = fopen(output_file, "wb");
			out_open = 1;
		}

		if(out != NULL)
		{
			if(mem1 != NULL && mem2 != NULL)
			{
				fread(mem1, 1, dumped_s, fp);
				fclose(fp);
				fp = fopen(original_file, "rb");
				if(fp)
				{
					original_s = file_size(fp);
					if(original_s == dumped_s)
					{
						uint8_t buf8 = 0;
						
						fread(mem2, 1, original_s, fp);
						
						for(i = ignore_begin; i < ignore_end; i++)
						{
							if(i < dumped_s)
							{
								mem1[i] = mem2[i] = 0x00;
							}
						}
						
						diff_sieve(mem1, mem2, original_s, &bs);
						bs_reset(&bs);
						
						fprintf(out, h_header, prefix_upper, prefix_upper);
	
						fprintf(out, "/* bitmap of differences between file assembled by FASM and original file by Microsoft */\nconst uint8_t vmm_%s[] = {\n\t", prefix);
						for(i = 0, j = 0; i < original_s; i += 8, j++)
						{
							buf8 = bs_read_bit(&bs, 8);
							
							if(j % 16 == 0)
							{
								fprintf(out, "\n\t");
							}
							fprintf(out, "0x%02X, ", buf8);
						}
						fprintf(out, "\n};\n\n");
						
						fprintf(out, h_footer, prefix_upper);
						
						status = EXIT_SUCCESS;
					}
					else
					{
						fprintf(stderr, "Error: file sizes of dump.bin and original.bin are not same\n");
					}
				}
				else
				{
					fprintf(stderr, "Error: file %s not found\n", original_file);
				}
			}
			else
			{
				fprintf(stderr, "Error: out of memory\n");
			}

			if(out_open)
			{
				fclose(out);
			}
		}
		else
		{
			fprintf(stderr, "Error: cannot open %s as output\n", output_file);
		}
	}
	else
	{
		fprintf(stderr, "Error: file %s not found\n", dump_file);
	}
	
	if(fp)
	{
		fclose(fp);
	}
	
	if(mem1) free(mem1);
	if(mem2) free(mem2);
	if(mem3) bs_mem_free(&bs);
	
	return status;
}
